home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / Tool Chest / Development Platforms / AppsToGo / AppsToGo.src / DTS.Lib / GWLayers.c < prev    next >
Encoding:
Text File  |  1993-06-18  |  31.9 KB  |  1,155 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        GWLayers.c
  6. ** Written by:  Eric Soldan and Forrest Tanaka
  7. **
  8. ** Copyright © 1989-1993 Apple Computer, Inc.
  9. ** All rights reserved.
  10. */
  11.  
  12. /* You may incorporate this sample code into your applications without
  13. ** restriction, though the sample code has been provided "AS IS" and the
  14. ** responsibility for its operation is 100% yours.  However, what you are
  15. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  16. ** after having made changes. If you're going to re-distribute the source,
  17. ** we require that you make it clear in the source that the code was
  18. ** descended from Apple Sample Code, but that you've made changes. */
  19.  
  20. /* This is an implementation of off-screen GWorld handling.  This particular
  21. ** implementation uses GWorlds in a hierarchical manner, with each layer in
  22. ** the hierarchy having its own tasks to handle at its specific level.
  23. ** The advantage to this is that it can conform to many applications.  Each
  24. ** application may need a different number of layers, and each layer may
  25. ** need to perform a different kind of operation.  By having an unlimited
  26. ** number of layers, and by having each layer handle its own application
  27. ** specific tasks, off-screen GWorld handling can be standardized.
  28. **
  29. ** A common use for off-screen stuff is to move an object around in a 
  30. ** window over a background.  To accomplish this, we need 3 layers.
  31. ** These are:
  32. **
  33. ** 1) The window layer.  This layer transfers a rectangle of pixels from
  34. **    the middle layer into the window layer, once the middle layer is ready.
  35. **    The rectangle transferred would be large enough to cover the old
  36. **    location and the new location, thus moving the piece without having
  37. **    to turn it off in the old location as a separate step.  This gives a
  38. **    very smooth appearance when moving an object.
  39. ** 2) A middle layer that is used to apply the object being moved to the
  40. **    background plus removing the object from the old location.  Once these
  41. **    two tasks are done, the off-screen work area is ready to be transferred
  42. **    to the window layer.
  43. ** 3) A background image against which the object moves.  This is used to
  44. **    restore the middle layer at the location where the object being moved
  45. **    was last at.
  46. **
  47. ** The top layer object relates to the window, and therefore we don't need an
  48. ** off-screen GWorld for it.  A call to create this layer might look like the below:
  49. **
  50. ** err = NewLayer(&windowLayer,   Layer object handle is returned here.
  51. **                nil,            Top layer, so there is no above layer.
  52. **                nil,            Uses default layer procedure.
  53. **                window,         Window used by the layer object.
  54. **                0,              Desired depth (0 for screen depth).
  55. **                0);             Custom layer init data, if any.
  56. **
  57. ** If NewLayer succeeds, the layer object handle is returned in windowLayer.
  58. ** If it fails, nil is returned in windowLayer, plus an error is returned.
  59. ** If windowLayer is successfully created, then we can proceed to create the
  60. ** next two layers.  In the case below, we are creating an off-screen layer
  61. ** that has a pixmap the same size and depth as windowLayer.  If this is
  62. ** what we want for the middle layer, then we can again use the default
  63. ** LayerProc for the kLayerInit message.  All we need to do is to call the
  64. ** default layerProc with a kLayerInit message.  We want the standard
  65. ** action for initialization, but we want our own update action.  That's
  66. ** why we have a custom layerProc for the middle layer.  The call would look
  67. ** something like the below:
  68. **
  69. ** err = NewLayer(&middleLayer,     Layer object handle is returned here.
  70. **                windowLayer,      Layer above this layer.
  71. **                MiddleLayerProc,  Custom layerProc.
  72. **                nil,              Create a pixmap for layer.
  73. **                0,                Pixmap created as same size/depth as above layer.
  74. **                0);
  75. **
  76. ** The background layer would be created similarly.  When you are finished with
  77. ** the layers, you can dispose of them one at a time with DisposeLayer, or you
  78. ** can dispose of all of them in the layer chain with DisposeThisAndBelowLayers.
  79. **
  80. ** Inserting a layer is done by position, and not by which layer it goes above
  81. ** or below.  The reason for this is that the layer positions are most likely
  82. ** absolute, and therefore it is better to indicate their position with an
  83. ** absolute number instead of always relating it to some other layer.  If it
  84. ** is necessary to insert a layer specifically above or below some other layer,
  85. ** it would be done as follows:
  86. **         InsertLayer(newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  87. **         InsertLayer(newLayer, belowLayer, GetLayerPosition(belowLayer));
  88. **
  89. ** The sample applications DTS.Draw and Kibitz uses the off-screen layer code.
  90. ** For a sample usage, see the file Window2.c in DTS.Draw, or Offscreen.c in Kibitz.
  91. */
  92.  
  93.  
  94.  
  95. /*****************************************************************************/
  96.  
  97.  
  98.  
  99. #ifndef __ERRORS__
  100. #include "Errors.h"
  101. #endif
  102.  
  103. #ifndef __GESTALTEQU__
  104. #include <GestaltEqu.h>
  105. #endif
  106.  
  107. #ifndef __GWLAYERS__
  108. #include "GWLayers.h"
  109. #endif
  110.  
  111. #ifndef __RESOURCES__
  112. #include <Resources.h>
  113. #endif
  114.  
  115. #ifndef __WINDOWS__
  116. #include <Windows.h>
  117. #endif
  118.  
  119. #define kQDOriginal 0
  120.  
  121. static OSErr    DefaultLayerInit(LayerObj theLayer);
  122. static OSErr    DefaultLayerDispose(LayerObj theLayer);
  123. static OSErr    DefaultLayerUpdate(LayerObj theLayer);
  124.  
  125. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds);
  126. static void        KillLayerWorld(LayerObj theLayer);
  127. static void        SmartGetGWorld(CGrafPtr *port, GDHandle *gdh);
  128. static void        SmartSetGWorld(CGrafPtr port, GDHandle gdh);
  129. static short    GetQDVersion(void);
  130.  
  131.  
  132.  
  133. /*****************************************************************************/
  134. /*****************************************************************************/
  135.  
  136.  
  137.  
  138. #pragma segment GWLayers
  139. OSErr    NewLayer(LayerObj *newLayer, LayerObj aboveLayer, LayerProc theProc,
  140.                  GrafPtr basePort, short depth, unsigned long theData)
  141. {
  142.     OSErr        err;
  143.     LayerRecPtr    lptr;
  144.     CGrafPtr    scratchPort;
  145.     GDHandle    baseGDevice;
  146.  
  147.     *newLayer = (LayerObj)NewHandleClear(sizeof(LayerRec));
  148.     if (err = MemError()) return(err);
  149.         /* If not enough memory for layer object, return nil and error. */
  150.  
  151.     SmartGetGWorld(&scratchPort, &baseGDevice);
  152.     if (!theProc)
  153.         theProc = DefaultLayerProc;
  154.             /* If layer proc is nil, then they want the default behavior. */
  155.  
  156.     lptr = **newLayer;
  157.     lptr->layerPort     = basePort;
  158.     lptr->layerGDevice  = baseGDevice;
  159.     lptr->layerDepth    = depth;
  160.     lptr->xferMode      = srcCopy;
  161.     lptr->layerProc     = theProc;
  162.     lptr->layerData     = theData;
  163.         /* Layer object is now initialized, except for layers that need a GWorld
  164.         ** created.  This will occur when the layer proc is called with an
  165.         ** initialization message.  (All fields not explicitly set are 0.) */
  166.  
  167.     InsertLayer(*newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  168.         /* Connect the layer to the layer chain.  The default initialization
  169.         ** behavior may need this, as it may create a GWorld of the same size
  170.         ** as the above layer.  If it isn't connected to the layer chain, then
  171.         ** there is no above layer. */
  172.  
  173.     if (err = (*theProc)(*newLayer, kLayerInit)) {
  174.         DisposeLayer(*newLayer);
  175.         *newLayer = nil;
  176.             /* There wasn't enough memory to create the off-screen GWorld, so
  177.             ** dispose of the layer object.  Since we failed, we need to return
  178.             ** nil and the error. */
  179.     }
  180.  
  181.     return(err);
  182. }
  183.  
  184.  
  185.  
  186. /*****************************************************************************/
  187.  
  188.  
  189.  
  190. #pragma segment GWLayers
  191. void    DetachLayer(LayerObj theLayer)
  192. {
  193.     LayerObj    aboveLayer, belowLayer;
  194.  
  195.     if (theLayer) {
  196.         aboveLayer = (*theLayer)->aboveLayer;
  197.         belowLayer = (*theLayer)->belowLayer;
  198.         if (aboveLayer)
  199.             (*aboveLayer)->belowLayer = belowLayer;
  200.         if (belowLayer)
  201.             (*belowLayer)->aboveLayer = aboveLayer;
  202.         (*theLayer)->aboveLayer = (*theLayer)->belowLayer = nil;
  203.     }
  204. }
  205.  
  206.  
  207.  
  208. /*****************************************************************************/
  209.  
  210.  
  211.  
  212. #pragma segment GWLayers
  213. OSErr    DisposeLayer(LayerObj theLayer)
  214. {
  215.     OSErr    err;
  216.  
  217.     err = noErr;
  218.     if (theLayer) {
  219.         err = (*((*theLayer)->layerProc))(theLayer, kLayerDispose);
  220.         DetachLayer(theLayer);
  221.         DisposeHandle((Handle)theLayer);
  222.     }
  223.  
  224.     return(err);
  225. }
  226.  
  227.  
  228.  
  229. /*****************************************************************************/
  230.  
  231.  
  232.  
  233. #pragma segment GWLayers
  234. OSErr    DisposeThisAndBelowLayers(LayerObj theLayer)
  235. {
  236.     OSErr    err, err2;
  237.  
  238.     err = noErr;
  239.     if (theLayer) {
  240.         err2 = DisposeThisAndBelowLayers((*theLayer)->belowLayer);
  241.         err  = DisposeLayer(theLayer);
  242.         if (!err)
  243.             err = err2;
  244.     }
  245.     return(err);
  246. }
  247.  
  248.  
  249.  
  250. /*****************************************************************************/
  251.  
  252.  
  253.  
  254. #pragma segment GWLayers
  255. short    GetLayerPosition(LayerObj theLayer)
  256. {
  257.     short    pos;
  258.  
  259.     if (!theLayer) return(0);
  260.  
  261.     for (pos = 0; theLayer = (*theLayer)->aboveLayer; ++pos);
  262.     return(pos);
  263. }
  264.  
  265.  
  266.  
  267. /*****************************************************************************/
  268.  
  269.  
  270.  
  271. #pragma segment GWLayers
  272. LayerObj    GetTopLayer(LayerObj theLayer)
  273. {
  274.     for (; (*theLayer)->aboveLayer; theLayer = (*theLayer)->aboveLayer);
  275.     return(theLayer);
  276. }
  277.  
  278.  
  279.  
  280. /*****************************************************************************/
  281.  
  282.  
  283.  
  284. #pragma segment GWLayers
  285. LayerObj    GetBottomLayer(LayerObj theLayer)
  286. {
  287.     for (; (*theLayer)->belowLayer; theLayer = (*theLayer)->belowLayer);
  288.     return(theLayer);
  289. }
  290.  
  291.  
  292.  
  293. /*****************************************************************************/
  294.  
  295.  
  296.  
  297. #pragma segment GWLayers
  298. void    InsertLayer(LayerObj theLayer, LayerObj referenceLayer, short pos)
  299. {
  300.     LayerObj    aboveLayer, belowLayer;
  301.     short        i;
  302.  
  303.     if (theLayer) {
  304.         if (theLayer == referenceLayer) {
  305.             /* If theLayer layer is the same as referenceLayer... */
  306.  
  307.             if (belowLayer = (*theLayer)->belowLayer)
  308.                 referenceLayer = belowLayer;
  309.             if (aboveLayer = (*theLayer)->aboveLayer)
  310.                 referenceLayer = aboveLayer;
  311.                     /* Try to make the reference layer not the same as theLayer.
  312.                     ** If it is the same as theLayer, then when theLayer is
  313.                     ** removed from the old hierarchy, we lose the ability to re-add
  314.                     ** it to the hierarchy in a new location. */
  315.         }
  316.  
  317.         DetachLayer(theLayer);
  318.             /* Remove layer from its old hierarchy, if any. */
  319.  
  320.         if (!referenceLayer) return;
  321.             /* If there isn't a valid alternative reference, then theLayer
  322.             ** IS the hierarchy and no action is taken. */
  323.  
  324.         aboveLayer = nil;
  325.         belowLayer = GetTopLayer(referenceLayer);
  326.             /* aboveLayer now nil.  belowLayer now is top layer.  These
  327.             ** are the correct values if the layer being added is to be
  328.             ** the new top layer.  This will be the case if pos is 0.
  329.             ** We now walk the linked list pos number of times to get the
  330.             ** correct position.  We also terminate if we reach the end
  331.             ** of the linked list, no matter what pos is.  This will allow
  332.             ** values of pos that are too big to insert the layer at the
  333.             ** end of the linked list. */
  334.  
  335.         for (i = 0; ((belowLayer) && (i != pos)); ++i) {
  336.             aboveLayer = belowLayer;
  337.             belowLayer = (*belowLayer)->belowLayer;
  338.         }
  339.             /* We now have correct values for aboveLayer and belowLayer.  Note that
  340.             ** these values may be nil, which would be correct. */
  341.         if ((*theLayer)->aboveLayer = aboveLayer)
  342.             (*aboveLayer)->belowLayer = theLayer;
  343.         if ((*theLayer)->belowLayer = belowLayer)
  344.             (*belowLayer)->aboveLayer = theLayer;
  345.     }
  346. }
  347.  
  348.  
  349.  
  350. /*****************************************************************************/
  351.  
  352.  
  353.  
  354. #pragma segment GWLayers
  355. OSErr    UpdateLayer(LayerObj theLayer)
  356. {
  357.     OSErr    err;
  358.  
  359.     err = noErr;
  360.     if (theLayer) {
  361.         err = UpdateLayer((*theLayer)->belowLayer);
  362.             /* Handle the updates from the bottom up. */
  363.         if (!err)
  364.             err = (*((*theLayer)->layerProc))(theLayer, kLayerUpdate);
  365.                 /* Chain possible errors through each level of recursion. */
  366.     }
  367.     return(err);
  368. }
  369.  
  370.  
  371.  
  372. /*****************************************************************************/
  373.  
  374.  
  375.  
  376. #pragma segment GWLayers
  377. Rect    GetEffectiveSrcRect(LayerObj theLayer)
  378. {
  379.     Rect    srcRect;
  380.  
  381.     if (!theLayer)
  382.         SetRect(&srcRect, 0, 0, 0, 0);
  383.     else {
  384.         srcRect = (*theLayer)->srcRect;
  385.         if (EmptyRect(&srcRect))
  386.             srcRect = ((*theLayer)->layerPort)->portRect;
  387.     }
  388.     return(srcRect);
  389. }
  390.  
  391.  
  392.  
  393. /*****************************************************************************/
  394.  
  395.  
  396.  
  397. #pragma segment GWLayers
  398. Rect    GetEffectiveDstRect(LayerObj theLayer)
  399. {
  400.     Rect    dstRect;
  401.  
  402.     if (!theLayer)
  403.         SetRect(&dstRect, 0, 0, 0, 0);
  404.     else {
  405.         dstRect = (*theLayer)->dstRect;
  406.         if (EmptyRect(&dstRect))
  407.             dstRect = ((*theLayer)->layerPort)->portRect;
  408.     }
  409.     return(dstRect);
  410. }
  411.  
  412.  
  413.  
  414. /*****************************************************************************/
  415.  
  416.  
  417.  
  418. #pragma segment GWLayers
  419. OSErr    DefaultLayerProc(LayerObj theLayer, short message)
  420. {
  421.     OSErr    err;
  422.  
  423.     err = noErr;
  424.     if (theLayer) {
  425.         switch (message) {        /* Dispatch to the correct default behavior. */
  426.             case kLayerInit:
  427.                 err = DefaultLayerInit(theLayer);
  428.                 break;
  429.             case kLayerDispose:
  430.                 err = DefaultLayerDispose(theLayer);
  431.                 break;
  432.             case kLayerUpdate:
  433.                 err = DefaultLayerUpdate(theLayer);
  434.                 break;
  435.             default:
  436.                 break;
  437.         }
  438.     }
  439.     return(err);
  440. }
  441.  
  442.  
  443.  
  444. /*****************************************************************************/
  445.  
  446.  
  447.  
  448. #pragma segment GWLayers
  449. static OSErr    DefaultLayerInit(LayerObj theLayer)
  450. {
  451.     LayerObj    aboveLayer;
  452.     GWorldPtr    layerWorld;        /* GWorld for this layer. */
  453.     Rect        parentRect;        /* Rectangle of parent in global coordinates. */
  454.     GrafPtr        parentPort;        /* Parent layer's GrafPort. */
  455.     GDHandle    parentGDevice;    /* Parent layer's GDevice. */
  456.     CGrafPtr    keepPort;        /* Saved GrafPort. */
  457.     GDHandle    keepGDevice;    /* Saved GDevice. */
  458.     Point        org;
  459.     OSErr        err;
  460.     short        depth;
  461.  
  462.     err = noErr;
  463.     if (theLayer) {
  464.         if (!(*theLayer)->layerPort) {
  465.  
  466.             if (aboveLayer = (*theLayer)->aboveLayer) {
  467.                 /* The default behavior is to create a GWorld the same size
  468.                 ** as the above layer, if there is one.  If there isn't an above
  469.                 ** layer and we were expected to create a GWorld, we have problems.
  470.                 ** This situation can't be resolved and is handled as a paramErr. */
  471.  
  472.                 if (!((*theLayer)->layerDepth))
  473.                     (*theLayer)->layerDepth = (*aboveLayer)->layerDepth;
  474.  
  475.                 SmartGetGWorld(&keepPort, &keepGDevice);        /* Keep the GWorld. */
  476.  
  477.                 parentPort    = (*aboveLayer)->layerPort;
  478.                 parentGDevice = (*aboveLayer)->layerGDevice;
  479.                     /* Grab the parent layer's GrafPort and GDevice. */
  480.     
  481.                 SmartSetGWorld((CGrafPtr)parentPort, parentGDevice);
  482.                 parentRect = GetEffectiveDstRect(aboveLayer);
  483.                     /* The default behavior is to use the portRect of the above
  484.                     ** port.  This behavior can be overridden if desired by setting
  485.                     ** dstRect.  dstRect is initialized to be empty, but if
  486.                     ** it is specifically set, then this layer should map into
  487.                     ** just the dstRect and not the portRect.  This is useful if
  488.                     ** the off-screen image is to be displayed in only a portion
  489.                     ** of a window. */
  490.  
  491.                 org.h = parentRect.left;
  492.                 org.v = parentRect.top;
  493.  
  494.                 LocalToGlobal(((Point *)&parentRect) + 0);
  495.                 LocalToGlobal(((Point *)&parentRect) + 1);
  496.                     /* Put the parent layer's destination rect in global coordinates. */
  497.     
  498.                 if (GetQDVersion())
  499.                     err = NewGWorld(&layerWorld, (*theLayer)->layerDepth, &parentRect, nil, nil, 0);
  500.                         /* Create the GWorld for this layer.  It will be created with the
  501.                         ** requested depth.  If the requested depth is 0, then it will be
  502.                         ** created with a depth great enough for the deepest monitor the
  503.                         ** parentRect intersects. */
  504.                 else
  505.                     err = MakeLayerWorld(&layerWorld, theLayer, parentRect);
  506.                         /* Create a bitmap for those systems without GWorlds. */
  507.  
  508.                 if (err == noErr) {
  509.                     (*theLayer)->layerOwnsPort = true;
  510.                     SetPort((*theLayer)->layerPort = (GrafPtr)layerWorld);
  511.                         /* Save the new GWorld in the layer object. */
  512.                     SetOrigin(org.h, org.v);
  513.                         /* Set the origin so that this GWorld maps directly into the
  514.                         ** area to be copied into (dstRect or portRect) for the
  515.                         ** above layer. */
  516.  
  517.                     if (!((*theLayer)->layerDepth)) {
  518.                         if (((GrafPtr)layerWorld)->portBits.rowBytes & 0x8000)
  519.                             depth = (*(((CGrafPtr)layerWorld)->portPixMap))->pixelSize;
  520.                         else
  521.                             depth = 1;
  522.                         (*theLayer)->layerDepth = depth;
  523.                     }
  524.                 }
  525.  
  526.                 SmartSetGWorld(keepPort, keepGDevice);        /* Restore the kept GWorld. */
  527.             }
  528.             else {
  529.                 err = paramErr;
  530.                     /* We were expected to create an off-screen GWorld of the
  531.                     ** same size as the above layer, but we didn't have an above
  532.                     ** layer.  This is an error.  The parameters passed to NewLayer
  533.                     ** were inappropriate for the situation, so return a paramErr. */
  534.             }
  535.         }
  536.     }
  537.  
  538.     return(err);
  539. }
  540.  
  541.  
  542.  
  543. /*****************************************************************************/
  544.  
  545.  
  546.  
  547. #pragma segment GWLayers
  548. Rect    UpdateUpdateRects(LayerObj theLayer)
  549. {
  550.     Rect    lastUpdate, thisUpdate, dstRect;
  551.  
  552.     if (theLayer) {
  553.         lastUpdate = (*theLayer)->lastUpdate;
  554.         (*theLayer)->lastUpdate = thisUpdate = (*theLayer)->thisUpdate;
  555.         SetRect(&((*theLayer)->thisUpdate), 0, 0, 0, 0);
  556.  
  557.         if ((*theLayer)->includeLastUpdate) {
  558.             (*theLayer)->includeLastUpdate = false;
  559.             if (EmptyRect(&lastUpdate))
  560.                 lastUpdate = thisUpdate;
  561.             if (EmptyRect(&thisUpdate))
  562.                 thisUpdate = lastUpdate;
  563.             UnionRect(&thisUpdate, &lastUpdate, &thisUpdate);
  564.                 /* We are going to update the last and current update rects.
  565.                 ** This will allow the appearance of movement for a foreground
  566.                 ** object.  The old location is cleared, plus the new location
  567.                 ** is updated. */
  568.             dstRect = GetEffectiveDstRect(theLayer);
  569.             SectRect(&thisUpdate, &dstRect, &thisUpdate);
  570.         }
  571.     }
  572.     else SetRect(&thisUpdate, 0, 0, 0, 0);
  573.  
  574.     return(thisUpdate);
  575. }
  576.  
  577.  
  578.  
  579. /*****************************************************************************/
  580.  
  581.  
  582.  
  583. #pragma segment GWLayers
  584. static OSErr    DefaultLayerUpdate(LayerObj theLayer)
  585. {
  586.     LayerObj    belowLayer;
  587.     GrafPtr        belowPort, thisPort;
  588.     GDHandle    thisGDevice;
  589.     CGrafPtr    keepPort;
  590.     GDHandle    keepGDevice;
  591.     Rect        thisUpdate, belowRect, thisRect;
  592.     short        xfer;
  593.     RgnHandle    rgn;
  594.  
  595.     /* The default update behavior is to copy the area to be updated from the
  596.     ** below layer into the indicated layer.  We only need to update layer if
  597.     ** there is a below layer.  The bottom-most layer update doesn't do anything.
  598.     ** As a default, the bottom-most layer is considered background and does not
  599.     ** get updated. */
  600.  
  601.     if (theLayer) {
  602.         if (belowLayer = (*theLayer)->belowLayer) {
  603.             /* Get this layer's GWorld and below layer's port. */
  604.             thisPort    = (*theLayer)->layerPort;
  605.             thisGDevice = (*theLayer)->layerGDevice;
  606.             belowPort   = (*belowLayer)->layerPort;
  607.  
  608.             /* Save current GWorld and set the parent's GWorld. */
  609.             SmartGetGWorld(&keepPort, &keepGDevice);
  610.             SmartSetGWorld((CGrafPtr)thisPort, thisGDevice);
  611.  
  612.             thisUpdate = UpdateUpdateRects(theLayer);
  613.  
  614.             rgn = NewRgn();
  615.             RectRgn(rgn, &thisUpdate);
  616.  
  617.             belowRect = GetEffectiveSrcRect(belowLayer);
  618.             thisRect  = GetEffectiveDstRect(theLayer);
  619.  
  620.                 /* As a default behavior, we CopyBits the below layer into this layer. */
  621.             LockLayerWorld(belowLayer);
  622.             LockLayerWorld(theLayer);
  623.             xfer = (*theLayer)->xferMode;
  624.             CopyBits(&belowPort->portBits, &thisPort->portBits, &belowRect, &thisRect, xfer, rgn);
  625.             UnlockLayerWorld(theLayer);
  626.             UnlockLayerWorld(belowLayer);
  627.             DisposeRgn(rgn);
  628.  
  629.             SmartSetGWorld(keepPort, keepGDevice);        /* Restore to the kept GWorld. */
  630.         }
  631.     }
  632.     return(noErr);
  633. }
  634.  
  635.  
  636.  
  637. /*****************************************************************************/
  638.  
  639.  
  640.  
  641. #pragma segment GWLayers
  642. static OSErr    DefaultLayerDispose(LayerObj theLayer)
  643. {
  644.     GWorldPtr    theWorld;
  645.  
  646.     if (theLayer) {
  647.         if ((*theLayer)->layerOwnsPort) {
  648.             if (theWorld = (GWorldPtr)(*theLayer)->layerPort) {
  649.                 if ((*theLayer)->layerBitmap)
  650.                     KillLayerWorld(theLayer);
  651.                 else
  652.                     DisposeGWorld(theWorld);
  653.             }
  654.         }
  655.     }
  656.  
  657.     return(noErr);
  658. }
  659.  
  660.  
  661.  
  662. /*****************************************************************************/
  663.  
  664.  
  665.  
  666. #pragma segment GWLayers
  667. void    InvalLayer(LayerObj theLayer, Rect invalRect, Boolean includeLastUpdate)
  668. {
  669.     Rect        thisUpdate, srcRect, dstRect;
  670.     LayerObj    belowLayer;
  671.     short        ow, oh;
  672.     long        dw, dh, sw, sh;
  673.  
  674.     if (theLayer) {
  675.         belowLayer = (*theLayer)->belowLayer;
  676.         dstRect    = GetEffectiveDstRect(theLayer);
  677.  
  678.         SectRect(&dstRect, &invalRect, &invalRect);
  679.         if (!EmptyRect(&invalRect)) {                /* If there is something to invalidate... */
  680.             thisUpdate = (*theLayer)->thisUpdate;    /* There may be a prior unhandled update... */
  681.             if (EmptyRect(&thisUpdate))
  682.                 thisUpdate = invalRect;                /* UnionRect doesn't */
  683.             UnionRect(&thisUpdate, &invalRect, &(*theLayer)->thisUpdate);    /* like empty rects. */
  684.  
  685.             if (belowLayer) {
  686.                 /* If we have a below layer, then pass the update down.  The effectiveSrcRct
  687.                 ** rect for the below layer may be a different size than the effectiveDstRct.
  688.                 ** If this is the case, we want to scale invalRect to invalidate a proportional
  689.                 ** area in the below layer. */
  690.  
  691.                 srcRect = GetEffectiveSrcRect(belowLayer);
  692.  
  693.                 dw = dstRect.right  - dstRect.left;        /* Calculate widths and heights for */
  694.                 dh = dstRect.bottom - dstRect.top;        /* srcRect and dstRect. */
  695.                 sw = srcRect.right  - srcRect.left;
  696.                 sh = srcRect.bottom - srcRect.top;
  697.  
  698.                 OffsetRect(&invalRect, -dstRect.left, -dstRect.top);
  699.                     /* We want to align the upper-left corner of the srcRect and dstRect
  700.                     ** so that the scaling also aligns the invalRect into the correct
  701.                     ** place in the below layer's effectiveSrcRect.  invalRect is now
  702.                     ** positioned relative to a dstRect with a upper-left corner of 0,0. */
  703.  
  704.                 if (dw != sw) {        /* Width dstRect different than srcRect. */
  705.                     ow = invalRect.right  - invalRect.left;
  706.                     invalRect.left  = (short)((invalRect.left  * sw) / dw);
  707.                     invalRect.right = (short)((invalRect.right * sw) / dw);
  708.                     if ((((invalRect.right  - invalRect.left) * dw) / sw) != ow)
  709.                         ++invalRect.right;
  710.                             /* We can possibly lose a fraction of a pixel on the right edge when
  711.                             ** scaling the invalRect.  It won't hurt if we inval just a bit too
  712.                             ** much, whereas invalidating too little is a bad thing. */
  713.                 }
  714.  
  715.                 if (dh != sh) {        /* Height dstRect different than srcRect. */
  716.                     oh = invalRect.bottom - invalRect.top;
  717.                     invalRect.top    = (short)((invalRect.top    * sh) / dh);
  718.                     invalRect.bottom = (short)((invalRect.bottom * sh) / dh);
  719.                     if ((((invalRect.bottom - invalRect.top ) * dh) / sh) != oh)
  720.                         ++invalRect.bottom;
  721.                 }
  722.  
  723.                 OffsetRect(&invalRect, srcRect.left, srcRect.top);
  724.                     /* Displace the new invalRect correctly relative to the srcRect. */
  725.             }
  726.         }
  727.  
  728.         if (includeLastUpdate)
  729.             (*theLayer)->includeLastUpdate = true;
  730.                 /* If requested to update last position as well, flag it. */
  731.  
  732.         InvalLayer(belowLayer, invalRect, includeLastUpdate);
  733.             /* Invalidate the below layer with the new (possibly scaled) invalRect. */
  734.     }
  735. }
  736.  
  737.  
  738. /*****************************************************************************/
  739.  
  740.  
  741.  
  742. #pragma segment GWLayers
  743. void    SetLayerWorld(LayerObj theLayer)
  744. {
  745.     CGrafPtr    keepPort;
  746.     GDHandle    keepGDevice;
  747.  
  748.     /* This is a convenient call for setting a GWorld, while remembering what
  749.     ** the previous GWorld was.  This should be balanced with a call to
  750.     ** ResetLayerWorld.  A count of how many times this is called is kept
  751.     ** so that the old GWorld is cached only if SetLayerWorld is currently
  752.     ** in balance with ResetLayerWorld.  This keeps the oldest kept GWorld
  753.     ** from being overwritten by subsequent calls. */
  754.  
  755.     if (theLayer) {
  756.         if (!(*theLayer)->cachedCount++) {
  757.             SmartGetGWorld(&keepPort, &keepGDevice);
  758.             (*theLayer)->cachedPort    = keepPort;
  759.             (*theLayer)->cachedGDevice = keepGDevice;
  760.         }
  761.         SmartSetGWorld((CGrafPtr)(*theLayer)->layerPort, (*theLayer)->layerGDevice);
  762.         LockLayerWorld(theLayer);
  763.     }
  764. }
  765.  
  766.  
  767.  
  768. /*****************************************************************************/
  769.  
  770.  
  771.  
  772. #pragma segment GWLayers
  773. void    ResetLayerWorld(LayerObj theLayer)
  774. {
  775.     /* This is used to undo a call to SetLayerWorld.  Calls to ResetLayerWorld
  776.     ** should be balanced with previous calls to SetLayerWorld. */
  777.  
  778.     if (theLayer) {
  779.         UnlockLayerWorld(theLayer);
  780.         if (!--(*theLayer)->cachedCount)
  781.             SmartSetGWorld((*theLayer)->cachedPort, (*theLayer)->cachedGDevice);
  782.     }
  783. }
  784.  
  785.  
  786.  
  787. /*****************************************************************************/
  788.  
  789.  
  790.  
  791. #pragma segment GWLayers
  792. void    LockLayerWorld(LayerObj theLayer)
  793. {
  794.     Handle    bitmap;
  795.  
  796.     /* This is a convenient way to lock down the pixels for a layer's GWorld.
  797.     ** A locked count is kept to make sure that the GWorld is locked only the
  798.     ** first time this is called.  Calls to LockLayerWorld will most likely
  799.     ** be balanced by calls to UnlockLayerWorld, but not necessarily.  It may
  800.     ** be desirable to keep a GWorld call locked.  In this case, right after
  801.     ** creating the layer (and indirectly its GWorld), call LockLayerWorld.
  802.     ** This will initially lock it.  Subsequent calls would be balanced, and
  803.     ** therefore there will always be one more LockLayerWorld call than
  804.     ** UnlockLayerWorld calls.  This will keep it locked. */
  805.  
  806.     if (theLayer) {
  807.         if ((*theLayer)->layerOwnsPort) {
  808.             if (!(*theLayer)->lockedCount++) {
  809.                 if (bitmap = (*theLayer)->layerBitmap) {
  810.                     HLock(bitmap);
  811.                     (*theLayer)->layerPort->portBits.baseAddr = *bitmap;
  812.                 }
  813.                 else
  814.                     LockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  815.             }
  816.         }
  817.     }
  818. }
  819.  
  820.  
  821.  
  822. /*****************************************************************************/
  823.  
  824.  
  825.  
  826. #pragma segment GWLayers
  827. void    UnlockLayerWorld(LayerObj theLayer)
  828. {
  829.     Handle    bitmap;
  830.  
  831.     /* This undoes what LockLayerWorld does.  Calls to UnlockLayerWorld will
  832.     ** generally be balanced with calls to LockLayerWorld. */
  833.  
  834.     if (theLayer) {
  835.         if ((*theLayer)->layerOwnsPort) {
  836.             if (!--(*theLayer)->lockedCount) {
  837.                 if (bitmap = (*theLayer)->layerBitmap)
  838.                     HUnlock(bitmap);
  839.                 else
  840.                     UnlockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  841.             }
  842.         }
  843.     }
  844. }
  845.  
  846.  
  847.  
  848. /*****************************************************************************/
  849.  
  850.  
  851.  
  852. #pragma segment GWLayers
  853. RgnHandle    ScreenDepthRegion(short depth)
  854. {
  855.     RgnHandle        retRgn, tmpRgn;
  856.     GDHandle        device;
  857.     PixMapHandle    pmap;
  858.     Rect            rct;
  859.     GrafPtr            mainPort;
  860.  
  861.     retRgn = NewRgn();
  862.  
  863.     if (GetQDVersion() == kQDOriginal) {
  864.         if (depth == 1) {
  865.             GetWMgrPort(&mainPort);
  866.             rct = mainPort->portRect;
  867.             RectRgn(retRgn, &rct);
  868.         }
  869.     }
  870.     else {
  871.         tmpRgn = NewRgn();
  872.         for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  873.             if (
  874.                 (TestDeviceAttribute(device, screenDevice)) &&
  875.                 (TestDeviceAttribute(device, screenActive))
  876.             ) {
  877.                 pmap = (*device)->gdPMap;
  878.                 if ((*pmap)->pixelSize >= depth) {
  879.                     rct = (*device)->gdRect;
  880.                     RectRgn(tmpRgn, &rct);
  881.                     UnionRgn(retRgn, tmpRgn, retRgn);
  882.                 }
  883.             }
  884.         }
  885.         DisposeRgn(tmpRgn);
  886.     }
  887.  
  888.     return(retRgn);
  889. }
  890.  
  891.  
  892.  
  893. /*****************************************************************************/
  894.  
  895.  
  896.  
  897. #pragma segment GWLayers
  898. CIconHandle    ReadCIcon(short iconID)
  899. {
  900.     Handle    hndl;
  901.  
  902.     if (GetQDVersion() == kQDOriginal) {
  903.         hndl = GetResource('cicn', iconID);
  904.         DetachResource(hndl);
  905.         return((CIconHandle)hndl);
  906.     }
  907.  
  908.     return(GetCIcon(iconID));
  909. }
  910.  
  911.  
  912.  
  913. /*****************************************************************************/
  914.  
  915.  
  916.  
  917. #pragma segment GWLayers
  918. void    KillCIcon(CIconHandle icon)
  919. {
  920.     if (!icon) return;
  921.  
  922.     if (GetQDVersion() == kQDOriginal)
  923.         DisposeHandle((Handle)icon);
  924.     else
  925.         DisposeCIcon(icon);
  926. }
  927.  
  928.  
  929.  
  930. /*****************************************************************************/
  931.  
  932.  
  933.  
  934. #pragma segment GWLayers
  935. void    DrawCIcon(CIconHandle icon, Rect destRect)
  936. {
  937.     if (!icon) return;
  938.  
  939.     if (GetQDVersion() == kQDOriginal)
  940.         DrawCIconByDepth(icon, destRect, 1, true);
  941.     else
  942.         PlotCIcon(&destRect, icon);
  943. }
  944.  
  945.  
  946.  
  947. /*****************************************************************************/
  948.  
  949.  
  950.  
  951. #pragma segment GWLayers
  952. void    DrawCIconNoMask(CIconHandle icon, Rect destRect)
  953. {
  954.     Rect    iconRect;
  955.     char    oldMask[128], *mptr;
  956.     short    maskSize, i;
  957.  
  958.     if (!icon) return;
  959.  
  960.     mptr = (Ptr)(*icon)->iconMaskData;
  961.     iconRect = (*icon)->iconPMap.bounds;
  962.     maskSize = (iconRect.bottom - iconRect.top) * (*icon)->iconMask.rowBytes;
  963.     for (i = 0; i < maskSize; ++i) {
  964.         oldMask[i] = mptr[i];
  965.         mptr[i] = 0xFF;
  966.     }
  967.     DrawCIcon(icon, destRect);
  968.     mptr = (Ptr)(*icon)->iconMaskData;
  969.     for (i = 0; i < maskSize; ++i) mptr[i] = oldMask[i];
  970. }
  971.  
  972.  
  973.  
  974. /*****************************************************************************/
  975.  
  976.  
  977.  
  978. #pragma segment GWLayers
  979. void    DrawCIconByDepth(CIconHandle icon, Rect destRect, short depth, Boolean useMask)
  980. {
  981.     GrafPtr        curPort;
  982.     char        savedIconState;
  983.     char        savedDataState;
  984.     short        offset;
  985.     BitMapPtr    bmap;
  986.     Rect        iconRect;
  987.  
  988.     if (!icon) return;
  989.  
  990.     GetPort(&curPort);
  991.  
  992.     if (!depth) {
  993.         if (!(curPort->portBits.rowBytes & 0x8000))
  994.             depth = 1;
  995.         else
  996.             depth = (*(((CGrafPtr)curPort)->portPixMap))->pixelSize;
  997.     }
  998.  
  999.     savedIconState = HGetState((Handle)icon);        /* Lock down things. */
  1000.     HLock((Handle)icon);
  1001.     if (depth > 1) {
  1002.         savedDataState = HGetState((*icon)->iconData);
  1003.         HLock((*icon)->iconData);
  1004.         (*icon)->iconPMap.baseAddr = *((*icon)->iconData);
  1005.             /* Point the icon's pixMap at the color icon data. */
  1006.     }
  1007.  
  1008.     iconRect = (*icon)->iconPMap.bounds;
  1009.         /* Find out the dimensions of the icon. */
  1010.  
  1011.     (*icon)->iconMask.baseAddr = (Ptr)(*icon)->iconMaskData;
  1012.         /* Point the mask's bitMap at the mask data. */
  1013.  
  1014.     offset  = iconRect.bottom - iconRect.top;
  1015.     offset *= (*icon)->iconMask.rowBytes;
  1016.     (*icon)->iconBMap.baseAddr = (*icon)->iconMask.baseAddr + offset;
  1017.         /* Point the icon's bitMap at the b/w icon data. */
  1018.  
  1019.     bmap = (depth == 1) ? (BitMapPtr)&((*icon)->iconBMap) : (BitMapPtr)&((*icon)->iconPMap);
  1020.     if (useMask)
  1021.         CopyMask(bmap, &((*icon)->iconMask), &curPort->portBits, &iconRect, &iconRect, &destRect);
  1022.     else
  1023.         CopyBits(bmap, &curPort->portBits, &iconRect, &destRect, srcCopy, nil);
  1024.  
  1025.     HSetState((Handle)icon, savedIconState);        /* Unlock things. */
  1026.     if (depth > 1)
  1027.         HSetState((*icon)->iconData, savedDataState);
  1028. }
  1029.  
  1030.  
  1031.  
  1032. /*****************************************************************************/
  1033.  
  1034.  
  1035.  
  1036. #pragma segment GWLayers
  1037. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds)
  1038. {
  1039.     GrafPtr    oldPort;
  1040.     GrafPtr    newPort;
  1041.     Handle    bitmap;
  1042.     OSErr    err;
  1043.  
  1044.     OffsetRect(&bnds, -bnds.left, -bnds.top);    /* Make sure upper-left is 0,0. */
  1045.  
  1046.     GetPort(&oldPort);        /* Need this to restore the port after OpenPort. */
  1047.  
  1048.     newPort = (GrafPtr)NewPtr(sizeof(GrafPort));        /* Allocate the grafPort. */
  1049.     if (err = MemError())
  1050.         return(err);        /* Failed to allocate the off-screen port. */
  1051.  
  1052.     /* The call to OpenPort does the following:
  1053.     ** 1) allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  1054.     ** 2) sets portBits to screenBits
  1055.     ** 3) sets portRect to screenBits.bounds, etc. (see IM I-163,164)
  1056.     ** 4) side effect: does a SetPort(&offScreen) */
  1057.  
  1058.     OpenPort(newPort);
  1059.     SetPort(oldPort);
  1060.  
  1061.         /* Now make bitmap the size of the bounds that caller supplied. */
  1062.  
  1063.     newPort->portRect = bnds;
  1064.     newPort->portBits.bounds = bnds;
  1065.     RectRgn(newPort->visRgn, &bnds);
  1066.  
  1067.     SetRectRgn(newPort->clipRgn, -32000, -32000, 32000, 32000);
  1068.         /* Avoid wide-open clipRgn, to be safe.    */
  1069.  
  1070.     /* rowBytes is size of row, it must be rounded up to an even number of bytes. */
  1071.     newPort->portBits.rowBytes = ((bnds.right - bnds.left + 15) >> 4) << 1;
  1072.  
  1073.     bitmap = NewHandle(newPort->portBits.rowBytes * (long)(bnds.bottom - bnds.top));
  1074.     if (err = MemError()) {
  1075.         ClosePort(newPort);            /* Dump the visRgn and clipRgn. */
  1076.         DisposPtr((Ptr)newPort);    /* Dump the GrafPort. */
  1077.         return(err);
  1078.     }
  1079.  
  1080.     (*theLayer)->layerBitmap = bitmap;
  1081.     *layerWorld              = (GWorldPtr)newPort;
  1082.  
  1083.     return(noErr);
  1084. }
  1085.  
  1086.  
  1087.  
  1088. /*****************************************************************************/
  1089.  
  1090.  
  1091.  
  1092. #pragma segment GWLayers
  1093. static void    KillLayerWorld(LayerObj theLayer)
  1094. {
  1095.     DisposeHandle((*theLayer)->layerBitmap);
  1096.     (*theLayer)->layerBitmap = nil;
  1097.  
  1098.     ClosePort((*theLayer)->layerPort);
  1099.     DisposePtr((Ptr)(*theLayer)->layerPort);
  1100.     (*theLayer)->layerPort = nil;
  1101. }
  1102.  
  1103.  
  1104.  
  1105.  
  1106. /*****************************************************************************/
  1107.  
  1108.  
  1109.  
  1110. #pragma segment GWLayers
  1111. static void    SmartGetGWorld(CGrafPtr *port, GDHandle *gdh)
  1112. {
  1113.     if (GetQDVersion())
  1114.         GetGWorld(port, gdh);
  1115.     else {
  1116.         *gdh = nil;
  1117.         GetPort((GrafPtr *)port);
  1118.     }
  1119. }
  1120.  
  1121.  
  1122.  
  1123. /*****************************************************************************/
  1124.  
  1125.  
  1126.  
  1127. #pragma segment GWLayers
  1128. static void    SmartSetGWorld(CGrafPtr port, GDHandle gdh)
  1129. {
  1130.     if (GetQDVersion())
  1131.         SetGWorld(port, gdh);
  1132.     else
  1133.         SetPort((GrafPtr)port);
  1134. }
  1135.  
  1136.  
  1137.  
  1138. /*****************************************************************************/
  1139.  
  1140.  
  1141.  
  1142. #pragma segment GWLayers
  1143. static short    GetQDVersion()
  1144. {
  1145.     long    gestaltResult;
  1146.  
  1147.     if (Gestalt(gestaltQuickdrawVersion, &gestaltResult))
  1148.         gestaltResult = 0;
  1149.  
  1150.     return((gestaltResult >> 8) & 0xFF);
  1151. }
  1152.  
  1153.  
  1154.  
  1155.